
#ifndef RT_USE_OLD_CONN_WRAP

#ifndef __RT_CONN_RLBTCP_PDU_H__
#define __RT_CONN_RLBTCP_PDU_H__

#include "RtByteStream.h"

const BYTE RT_CONN_RLBTCP_PDU_CONN_REQ			= 0x41;
const BYTE RT_CONN_RLBTCP_PDU_CONN_RESP			= 0x42;
const BYTE RT_CONN_RLBTCP_PDU_DISCONN			= 0x43;
const BYTE RT_CONN_RLBTCP_PDU_KEEPALIVE			= 0x44;
const BYTE RT_CONN_RLBTCP_PDU_DATA				= 0x45; // Not include ackNo;
const BYTE RT_CONN_RLBTCP_PDU_DATA_WITH_ACK		= 0x46; // Include ackNo;
const BYTE RT_CONN_RLBTCP_PDU_DATA_NEED_ACK		= 0x47; // Include ackNo;
const BYTE RT_CONN_RLBTCP_PDU_RTT				= 0x48; 

class CRtConnRlbTcpPduBase
{
public:
	CRtConnRlbTcpPduBase(BYTE inType) : m_type(inType) {}
	~CRtConnRlbTcpPduBase() {}
	
	static DWORD GetFixLength(BYTE inType)
	{
		switch(inType)
		{
#ifdef RLBTCP_ENABLE_SHORT_DATALEN
		case RT_CONN_RLBTCP_PDU_DATA:
			return 2; // TYPE(1) + SHORT_LEN(1)
		case RT_CONN_RLBTCP_PDU_DATA_WITH_ACK:
			return 4; // TYPE(1) + ACK(2) + SHORT_LEN(1)
		case RT_CONN_RLBTCP_PDU_DATA_NEED_ACK:
			return 4; // TYPE(1) + ACK(2) + SHORT_LEN(1)
#else
		case RT_CONN_RLBTCP_PDU_DATA:
			return 5; // TYPE(1) + DATA_LEN(4)
		case RT_CONN_RLBTCP_PDU_DATA_WITH_ACK:
			return 7; // TYPE(1) + ACK(2) + DATA_LEN(4)
		case RT_CONN_RLBTCP_PDU_DATA_NEED_ACK:
			return 7; // TYPE(1) + ACK(2) + DATA_LEN(4)
#endif
		case RT_CONN_RLBTCP_PDU_CONN_REQ:
			return 11; // TYPE(1) + ATTR(2) + CHANNEL(2) + ACK(2) + TICKET(4)
		case RT_CONN_RLBTCP_PDU_CONN_RESP:
			return 13; // TYPE(1) + RESULT(4) + CHANNEL(2) + ACK(2) + TICKET(4)
		case RT_CONN_RLBTCP_PDU_DISCONN:
			return 1; // TYPE(1)
		case RT_CONN_RLBTCP_PDU_KEEPALIVE:
			return 3; // TYPE(1) + ACK(2)
		case RT_CONN_RLBTCP_PDU_RTT:
			return 5; // TYPE(1) + RTT(4)
		default:
			return 0;
		}
	}

	BYTE GetType() const { return m_type; }

protected:
	BYTE	m_type;
};

class CRtConnRlbTcpPduConnReq : public CRtConnRlbTcpPduBase
{
public:
	CRtConnRlbTcpPduConnReq(
		WORD inConnAttr,
		WORD inChannelId,
		SeqType inAck, 
		DWORD inTicket);
	CRtConnRlbTcpPduConnReq();
	~CRtConnRlbTcpPduConnReq();

	void Encode(CRtMessageBlock& outData);
	void Decode(CRtMessageBlock& inData);

	WORD GetConnAttr() const { return m_connAttr; }
	WORD GetChannelId() const { return m_channelId; }
	SeqType GetAck() const { return m_ack; }
	DWORD GetTicket() const { return m_ticket; }

protected:
	WORD m_connAttr;
	WORD m_channelId;
	SeqType	m_ack;
	DWORD m_ticket;
};

class CRtConnRlbTcpPduConnResp : public CRtConnRlbTcpPduBase
{
public:
	CRtConnRlbTcpPduConnResp(
		RtResult inResult, 
		WORD inChannelId,
		SeqType inAck,
		DWORD inTicket);
	~CRtConnRlbTcpPduConnResp();
	CRtConnRlbTcpPduConnResp();

	void Encode(CRtMessageBlock& outData);
	void Decode(CRtMessageBlock& inData);

	RtResult GetResult() const { return m_result; }
	WORD GetChannelId() const { return m_channelId; }
	SeqType GetAck() const { return m_ack; }
	DWORD GetTicket() const { return m_ticket; }

protected:
	RtResult m_result;
	WORD m_channelId;
	SeqType	m_ack;
	DWORD m_ticket;
};

class CRtConnRlbTcpPduDisconn : public CRtConnRlbTcpPduBase
{
public:
	CRtConnRlbTcpPduDisconn();
	~CRtConnRlbTcpPduDisconn();

	void Encode(CRtMessageBlock& outData);
	void Decode(CRtMessageBlock& inData);
};

class CRtConnRlbTcpPduKeepalive : public CRtConnRlbTcpPduBase
{
public:
	CRtConnRlbTcpPduKeepalive(SeqType inAck);
	CRtConnRlbTcpPduKeepalive();
	~CRtConnRlbTcpPduKeepalive();

	void Encode(CRtMessageBlock& outData);
	void Decode(CRtMessageBlock& inData);

	SeqType GetAck() const { return m_ack; }

protected:
	SeqType	m_ack;
};

class CRtConnRlbTcpPduData: public CRtConnRlbTcpPduBase
{
public:
	CRtConnRlbTcpPduData(BYTE inType, CRtMessageBlock* inData, DWORD inDataLen);
	CRtConnRlbTcpPduData(BYTE inType = RT_CONN_RLBTCP_PDU_DATA);
	~CRtConnRlbTcpPduData();

	void Encode(CRtMessageBlock& outData);
	void DecodeFixLength(CRtMessageBlock& inData);

	void Initialize(BYTE inType, CRtMessageBlock* inData, DWORD inDataLen)
	{
		m_type = inType;
		m_ack = 0;		
#ifdef RLBTCP_ENABLE_SHORT_DATALEN
		m_shortLength = (inDataLen<0xFF ? (BYTE)inDataLen : 0xFF);
#endif
		m_length = inDataLen;
		m_data = inData;
	}
	void Release()
	{
		if (m_data)
		{
			m_data->DestroyChained();
			m_data = NULL;
		}
	}

	void SetAck(SeqType inAck) { m_ack = inAck; }
	SeqType GetAck() const { return m_ack; }

#ifdef RLBTCP_ENABLE_SHORT_DATALEN
	BYTE GetShortLength() const { return m_shortLength; }
#endif
	DWORD GetLength() const { return m_length; }

protected:
	/// Following members are ranged for memory border alignment optimization.
#ifdef RLBTCP_ENABLE_SHORT_DATALEN
	BYTE m_shortLength;
#endif
	SeqType	m_ack;
	DWORD m_length;
	CRtMessageBlock* m_data;
}; 

class CRtConnRlbTcpPduRtt : public CRtConnRlbTcpPduBase
{
public:
	CRtConnRlbTcpPduRtt(DWORD inTimestamp = 0);
	virtual ~CRtConnRlbTcpPduRtt();

	void Encode(CRtMessageBlock& outData);
	void Decode(CRtMessageBlock& inData);

	DWORD GetTimestamp() const { return m_timestamp; }

protected:
	DWORD m_timestamp;
};

#endif//!__RT_CONN_RLBTCP_PDU_H__

#endif // !RT_USE_OLD_CONN_WRAP
